mysql innodb日志模块介绍

简单介绍一下mysql的日志系统。我们都知道在数据库的生产环境上,可能会发生一些事故。例如之前有个同事在执行数据订正的时候,不小心将很多的订单数据中的凭证数据覆盖成了空。这样的操作第一时间肯定是想通过数据库备份的形式将数据恢复出来,这个时候你的DBA可能会告诉你,有一周的数据的备份。不幸的是,这个事故发生的情况并没有在一星期之内定位到原因。所幸,有一份较久的备份,DBA可以根据这个备份恢复到丢失前的那个节点。那么这里就需要提到mysql的日志系统是如何实现的,只介绍一下概念,具体的实践由伟大的DBA完成。

mysql的日志模块以及如何保证一致性

mysql的日志主要分为物理日志redo log(重做日志)和bin log(归档日志)。这两种日志都是只针对更新操作进行记录,针对查询的记录不会记录到mysql的日志模块。更新语句执行的主要流程:

cmd-markdown-logo

redo log(重做日志)

这个是只针对数据库引擎innodb才有的日志模块。我们可以类比我们在记账的时候,我们有一个账本,记录了每个顾客的账户余额记录,但是如果人特别多的时候我们很难找到每个顾客的记录然后做个更新操作(这里一次查询io一次更新io),最好的办法是将这次的消费记录更新计算的结果记录到一个“白板”上面,等到空闲的时候再去写账本(sync同步到数据库磁盘)。这个“白板”的功能就是redo log。当然这个“白板”也会有写完的时候,实际情况下redo log文件是存在物理文件中的,假设我们有四个redo log文件总共大小为4g,那么每个文件的容量为1g。

cmd-markdown-logo

粉板和账本配合的整个过程,其实就是 MySQL 里经常说到WAL 技术,WAL 的全称是 Write-Ahead Logging,它的关键点就是先写日志,再写磁盘,也就是先写粉板,等不忙的时候再写账本。有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为crash-safe。

bin log(归档日志)

可以简单理解为是记录了又一句的更新sql语句,当你需要进行恢复的时候可以先将表恢复到某个历史时间点,然后通过bin log中的记录一个个去执行到丢失数据前的时间点。那么这两种日志有什么不同,为什么要做区分?

1.redo log是物理日志,记录了在某行做了修改的结果(修改后的记录)。而bin log是逻辑日志,记录了在某行做了什么操作(执行修改的操作)。

2.redo log是InnoDB 引擎特有的,而bin log是基于mysql的server引擎的,所有的引擎都有选择启用或者关闭这个日志功能。

3.redo log是循环写的,如果point重合的话是会强制sync到磁盘的,但是bin log是会一直往下写的。

两阶段提交

介绍了两种日志模块的功能,我们再来分析开头为什么要做两阶段提交。我们在系统交互的过程中有没有碰到一种情况就是两个任务需要同时完成才算是完成,如果由于异常失败了其中一个,那么整个过程是不成功的,这里我们通常会用一个中间状态来控制整个事务。也就是两阶段提交日志的概念,将写bin log和redo log整个当成一个事务去处理。

redo log更新成功,binlog更新的时候mysql重启,重启机制检测到之后回滚该事务。redo log更新和bin log更新都成功,提交的时候mysql重启,重启之后检测到该事务已经完成自动提交。那么两个日志模块的数据是始终一致的。

如果不进行两阶段提交,数据库在异常重启之后恢复的正是库可能和通过bin log恢复的备份数据是不一致的。

总结

主要介绍了mysql innodb在更新操作的时候是如果记录日志,防止突然的重启以及后续的数据备份恢复。即时突然重启,redo log也记录了原始的物理修改信息。当然如果想要恢复到历史的某一个点,也可以通过bin log的形式在历史某一个版本的数据上进行迭代执行。两个日志模块通过了中间状态进行两阶段提交,同时也保证了数据的一致性(这里如果是分各自提交会有问题,数据不一致)。

  1. Date current = new Date();
  2. Calendar calendar = new GregorianCalendar();
  3. calendar.setTime(current);
  4. calendar.add(calendar.DATE, 1);